from django.db import connection
from .models import LunchItem
from .sql import generate_sql

class Order:
  def __init__(self, item, mentor, customer, quantity):
    self.item = item
    self.mentor = mentor
    self.customer = customer
    self.quantity = quantity
    self.group_orders_count = 0

def get_lunch_items_name_array():
    items = LunchItem.objects.all()
    return list(map(lambda x: x.name, items))

def get_sorted_orders(order_by_item_first = True):
    """
      Select lunch order records from database
      
      Args:
        order_by_item_first: order by lunch item first or last
      
      Returns:
        The dict array of db data
    """

    cursor = connection.cursor()
    cursor.execute(generate_sql(order_by_item_first))
    rows = cursor.fetchall()

    rslt = []
    for row in rows:
        _, item, _, mentor, _, customer, subtotal = row
        rslt.append(Order(item, mentor, customer, subtotal))

    return rslt

def calculate_total_from_number(order_rows, items_name_array):
    dict = {}
    # print(rows)
    for itemname in items_name_array:
        filter_rows = list(filter(lambda x: x.item == itemname, order_rows))
        map_array = list(map(lambda x: x.quantity, filter_rows))
        dict[itemname] = sum(map_array)

    return dict

def calculate_total_from_dict(order_rows, items_name_array):
    dict = {}
    for row in order_rows:
        row_q_dict = row.quantity
        for itemname in items_name_array:
            if row_q_dict.get(itemname) is not None:
                if dict.get(itemname) is None:
                  dict[itemname] = 0
                dict[itemname] += row_q_dict.get(itemname)

    return dict

def is_new_group_start(last_row, row):
    """
      To test if the row is the start of a new group or not

      Args:
        last_row: the last row
        row: current new row
      
      Return:
        True: a new group start from this row
    """

    if last_row == None or last_row.mentor == '-':
        return False
    elif last_row.item != row.item or last_row.mentor != row.mentor:
          return True
    return False

def on_new_group_start_in_matrix(new_rows, last_row, order_rows, items_name_array):
    filter_rows = list(filter(lambda x: x.mentor == last_row.mentor, order_rows))
    new_rows.append(Order(
        last_row.item,
        last_row.mentor,
        'total',
        calculate_total_from_dict(filter_rows, items_name_array)
    ))

def on_new_group_start_in_list(new_rows, last_row, order_rows, _):
    filter_rows = list(filter(lambda x: x.item == last_row.item and x.mentor == last_row.mentor, order_rows))
    map_array = list(map(lambda x: x.quantity, filter_rows))
    new_rows.append(Order(
        last_row.item,
        last_row.mentor,
        'total',
        sum(map_array)
    ))

def iterate_rows(order_rows, items_name_array, is_new_group_callback, on_new_group_callback):
    new_rows = []
    last_row = None
    for row in order_rows:
        if is_new_group_callback(last_row, row):
            on_new_group_callback(new_rows, last_row, order_rows, items_name_array)

        new_rows.append(Order(row.item, row.mentor, row.customer, row.quantity))
        last_row = row

    if last_row.mentor != '-':
        on_new_group_callback(new_rows, last_row, order_rows, items_name_array)

    return new_rows
    
def add_total_rows_in_matrix(order_rows, items_name_array):
    return iterate_rows(order_rows, items_name_array, is_new_group_start, on_new_group_start_in_matrix)

def add_total_rows_in_list(order_rows):
    return iterate_rows(order_rows, None, is_new_group_start, on_new_group_start_in_list)

def update_rows_count(order_rows):
    last_row = None
    for row in order_rows:
        if last_row is None or last_row.item != row.item or last_row.mentor != row.mentor:
            if row.mentor != '-':
              row.group_orders_count = len(list(filter(lambda x: x.item == row.item and x.mentor == row.mentor, order_rows)))
        last_row = row

    return order_rows

def cross_rows(order_rows):
    """
      Just like the Pivot Table function in Excel
      or
      crosstab function in PostgreSQL
      
      Expand the 1 dimension vertical data set into 2 dimension pivot table

      Args:
        order_rows: Order array
      
      Returns:
        Expanded Order Array
    """

    new_rows = []
    last_row = None
    for row in order_rows:
        if last_row == None or last_row.customer != row.customer or last_row.mentor != row.mentor:
            new_rows.append(Order('order', row.mentor, row.customer, { }))
      
        item = new_rows[-1]
        item.quantity[row.item] = row.quantity

        last_row = row
        
    return new_rows
